<script>
import { Draggable } from 'draggable-vue-directive'
import mutil        from '../utils/mutil';
// import { PageItemCommonStyle } from 'jzl-web-components';
import NodeDataValue from './ele/node-data-value';
import NodeFormulaRender from './ele/node-formula-render';
import BuilderNodesProp from './builder-nodes-prop';
import BuilderNodesAdd  from "./builder-nodes-add"
import BuilderNodesAddTools  from "./builder-nodes-add-tools"
import BuilderNodesLowcode from "./builder-nodes-lowcode";
import BuilderNodePropext from './builder-node-propext';
import BuilderCompsCloud from './builder-comps-cloud';
import PageItemPicker   from './pages/page-item-picker';

// import TPL_NODES from '../utils/tpl-nodes';
import tplCate      from '../utils/tpl-cate'

export default {
  name: "builder-nodes",
  props: {
    pageType: [ String, Number ],
    currentItem: Object,
    currentPage: Object,
    currentItemElCode: String,
    currentItems: Array,
    elemNodes: {
      type: [ Array, Object ],
      default: []
    },
    pageWidth: {
      type: Number,
      default: 1920
    },
    pageHeight: {
      type: Number,
      default: 1080
    }
  },
  data() {
    return {
      nodeTreeSetting: {
        label: 'name',
        // children: 'childs'
      },
      collapse: false,
      currentEleData: {},
      currentNode: {},
      expandKeys: [],
      popData: null,
      nodesPropShow: true,
      propTab: 'style',
      moving: false,
      nodeTreeDragProp: {
        boundingElement: document.body,
        handle: null,
        onPositionChange: this.onPosChanged
      },
      tempExpand: false,
      hoverExpand: false,
      panelFixed: true,
      tempExpandTimer: null,
      hoverExpandTimer: null,
      isNodeHover: false,
      hoverTimeout: null,

      tplCate: tplCate,
      compAddPanelShow: false,

      nodeActionPopVisible: false,
      nodeValuePopVisible: false,
      nodeEventPopVisible: false,
      nodeLowcodePopVisible: false,
      nodeFormulaPopVisible: false,

      compPanelName: "选择云组件",
      compPanelShow: false,
      isCreateMicroComp: false,

      pageItemSelectWinShow: false
    }
  },
  computed: {
    isDataEnable() {
      return this.isDataNode(_.get(this.currentNode, 'def'));
    },
  },
  directives: {
    Draggable,
  },
  components: {
    NodeDataValue,
    NodeFormulaRender,
    BuilderNodesProp,
    BuilderNodesAdd,
    BuilderNodesAddTools,
    BuilderNodesLowcode,
    BuilderNodePropext,
    BuilderCompsCloud,
    PageItemPicker
  },
  mounted() {
    this.$nextTick(() => {
      this.nodeTreeDragProp.handle = this.$refs.nodeTreeDragHandler;
      this.nodeTreeDragProp.onDragStart = () => {
        this.moving = true;
      }

      this.nodeTreeDragProp.onDragEnd = (positionDiff, absolutePosition, event) => {
        this.moving = false;

        if(absolutePosition && absolutePosition.top < 0) {
          this.$el.style.top = "0px";
        }

        if(absolutePosition && absolutePosition.left < 100) {
          this.$el.style.left = "0px";
          this.$el.style.top = "41px";
          this.panelFixed = true;

          this.$emit('pinMenuChange', true);
        } else {
          this.panelFixed = false;
          this.$emit('pinMenuChange', false);
        }
      }
    })
  },
  watch: {
    currentItemElCode(code) {
      this.$refs.nodesTree.setCurrentKey(code);

      if(!this.isNodeHover) this.expandKeys = [ code ];

      // this.initElemCurrentNode();

      let nodeData = this.$utils.getTreeData(this.elemNodes, "code", this.currentItemElCode);
      let currentEleData = _.get(nodeData, 'def');
      this.currentEleData = currentEleData || {};
      this.currentNode = nodeData;
      this.popData = nodeData;
      this.handleTempExpand();
      this.showNodeActionPopover();
    },
    nodesPropShow(val) {
      if(!val) return;
      let screenWidth = window.screen.width;
      let rect = this.$el.getBoundingClientRect();
      // let width = rect.width;
      // let height = rect.height;
      let left = rect.left;
      let right = rect.right;
      let distance = 350 - (screenWidth - right);

      if(distance > 0 && this.$el && this.$el.style) {
        this.$el.style.left = `${ left - distance }px`;
      }
    }
  },
  methods: {
    ...mutil,
    onPosChanged(positionDiff, absolutePosition, event) {   // 解决超出边界无法找到面板的bug
      this.hideNodeMorePopover();
    },
    hasActionLimitData(data, actionType = 'div') {
      // let popData = this.popData;
      let nodeType = _.get(data, "def._node") || _.get(data, "def._component");
      // let parentDef = _.get(this.popData, "parentDef");
      // if(_.indexOf([ 'div', 'text', 'icon', 'img', 'video', 'button' ], actionType) >= 0) {
      if(_.indexOf([ 'text', 'icon', 'img', 'video' ], nodeType) >= 0) {
        return false;
      }
      return true;
    },
    hasActionLimit(actionType) {
      return this.hasActionLimitData(this.popData, actionType)
    },
    getCurrentItem(node) {
      if(!node) return;

      let isRoot  = _.get(node, "data.isRoot");
      let item    = _.get(node, "data.item");
      let items   = _.get(node, "data.items");
      let parent  = _.get(node, "parent");

      if(isRoot) return { item, items };

      return this.getCurrentItem(parent);
    },
    clearSelectEleNodeHoverTimeout() {
      if(this.hoverTimeout) {
        clearTimeout(this.hoverTimeout);
        this.hoverTimeout = null;
      }
    },
    handleSelectEleNodeHover(data, node) {
      this.$emit('hoverElenode', data);
    },
    handleSelectEleNodeClick(data, node, vueObj, isHover = false) {
      // console.log(`===> isHover: ${ isHover }`);
      let nodeCode =  _.get(data, 'code');
      this.isNodeHover = isHover || false;

      if(!this.isNodeHover) this.expandKeys = [ nodeCode ];

      this.$emit('selectElenode', data);

      let info = this.getCurrentItem(node);

      if(info) this.$emit("selectItem", info);
      // this.currentItemElCode = _.get(data, 'code');

      this.popData = data;

      let currentCode = _.get(data, "code");
      let popCode = _.get(this.popData, "code");

      if(currentCode !== popCode) {
        this.hideNodeMorePopover();
      }
    },
    showNodeMorePopover(e, data, isActionBtn = false) {

      let $npop = this.$refs.nodeMorePopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);

      if(!isActionBtn) {
        this.popData = data;
      }

      // this.hideNodeDataPopover();
      this.$nextTick(() => {
        //显示新的
        // console.log(typeof this.$refs.nodesTreeContainer);
        let $refer = isActionBtn ? e.target.parentNode : this.$refs.nodesTreeContainer;
        $npop.referenceElm = $npop.$refs.reference = $refer // e.target.parentNode;
        $npop.showPopper = true;
        $npop.$emit('input', true);
        $npop.doShow();
      })
    },
    hideNodeMorePopover() {
      let $npop = this.$refs.nodeMorePopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);
    },
    getClosestVisibleEle(ele, idx = 0) {
      if(!ele) return null;
      if(idx > 5) return null;
      if(!idx) idx = 0;

      let style = window.getComputedStyle(ele);
      if(_.get(style, 'display') === 'none') {
        return this.getClosestVisibleEle(ele.parentNode, ++idx);
      } else {
        return ele;
      }
    },
    showNodeActionPopover() {
      let $npop = this.$refs.nodeActionPopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);

      let focusCode = this.currentItemElCode;
      if(!focusCode) return;

      let $eles = document.querySelectorAll(`[j-name=${ focusCode }]`);
      let $refer = this.getClosestVisibleEle(_.get($eles, '[0]'));
      if(!$refer) return;

      console.log($refer)

      // this.hideNodeDataPopover();
      this.$nextTick(() => {
        //显示新的
        // console.log(typeof this.$refs.nodesTreeContainer);
        $npop.referenceElm = $npop.$refs.reference = $refer; // e.target.parentNode;
        $npop.showPopper = true;
        $npop.$emit('input', true);
        $npop.doShow();
      })
    },
    hideNodeActionPopover() {
      let $npop = this.$refs.nodeActionPopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);
    },
    handleShowNodeIconWin() {
      this.$IconSpace({
        onSelect: (icon) => {
          if(this.currentEleData && this.currentEleData._ss) {
            this.currentEleData._ss.icon = icon;
          }
        }
      });
    },
    handleShowNodeImgWin() {
      this.$FileSpace({
        onSelect: (img) => {
          let filePath = _.get(img, "file_path");
          if(this.currentEleData && this.currentEleData._ss && filePath) {
            this.currentEleData._ss.image = filePath;
          }
        }
      });
    },
    handleClearNodeProp(type) {
      if(!this.currentEleData || !this.currentEleData._ss) return;
      if(type === 'icon') {
        this.currentEleData._ss.icon = "";
      } else if(type === 'img') {
        this.currentEleData._ss.image = "";
      }
    },
    isFixNode(data) {
      let def = _.get(data, "def")
      let code = _.get(data, "code") || _.get(def, "_code");
      let isFix = _.get(def, "_fix");

      if(!code || isFix) return true;

      let nodes = this.$utils.getTreePath(code, this.elemNodes, "code");

      let idx = _.findIndex(nodes, { _fix: "all" });

      return idx >= 0;
    },
    getCurrentItemIndex() {
      let itemCode = _.get(this.currentItem, 'page_item_code');
      if(!itemCode) return -1;
      return _.findIndex(this.currentItems, { page_item_code: itemCode });
    },
    handleRemoveSelected() {
      this.handleRemove(this.popData);
    },
    handleRemoveItem(item) {
      let itemCode = _.get(item, 'page_item_code');
      if(!itemCode) return -1;
      let idx = _.findIndex(this.currentItems, { page_item_code: itemCode });

      if(idx < 0) return;

      this.currentItems.splice(idx, 1);
      // this.updateMask();
      // this.handleSelectItem();
      // this.$forceUpdate();
      this.$emit("selectItem", {});
      this.$emit("eleNodeTreeChange");
    },
    handleRemove(data) {
      if(!data) return;

      if(data.isRoot) {
        return this.handleRemoveItem(data.item);
      }

      let def = _.get(data, "def");
      let parentDef = _.get(data, "parentDef");
      let code = _.get(data, "code");

      if(!def || !parentDef || !code) return;

      for(let p in parentDef) {
        let child = _.get(parentDef, p);

        if(child && child._code && child._code === code) {
          delete parentDef[ p ];
          break;
        }
      }

      let expandKeys = [ _.get(parentDef, "_code") ];

      for(let p in parentDef) {
        let child = _.get(parentDef, p);
        if(child && child._code) expandKeys.push(child._code);
      }
      this.hideNodeMorePopover();
      this.hideNodeActionPopover();
      this.$emit("changeElemNodes");

      this.$nextTick(() => {
        this.expandKeys = expandKeys;
      })
    },
    handleNameChg(data) {

      if(!data) return;

      let name = _.get(data, "name");
      let def = _.get(data, "def");

      data.nameEditing = false;

      if(!def) return;
      def._name = name;
    },
    getNodeRootCode(node) {
      let root = this.getItemRootByNode(node);
      return _.get(root, "data.code");
    },
    allowDrop(draggingNode, dropNode, type) {
      let dropData = _.get(dropNode, "data");
      let dropDataDef = _.get(dropData, "def");
      let dropNodeIsRoot = _.get(dropData, "isRoot");
      let dropNodeName = _.get(dropData, "name");
      let dropNodeType = _.get(dropDataDef, "_node");
// console.log("-------------------->>>>>>>>>----------------------");
// console.log(draggingNode, dropNode, type)
// console.log(draggingNode.parent);
      let dragIsRoot = _.get(draggingNode, "data.isRoot");

      if(type === 'inner') {
        if(_.indexOf([ 'text', 'icon', 'img' ], dropNodeType) >= 0) return false;
        if(dragIsRoot) {
          // 只能放 layout 下
          if(dropNodeName && dropNodeName !== 'jzlLayout') {
            return false;
          }
        } else {
          // layout 下只能是组件
          if(!dropNodeName || dropNodeName === 'jzlLayout') {
            return false;
          }
        }

        // 不能放 grid, slider 的wrap 中
        let subs = _.get(dropData, "children");

        if(subs && subs.length) {
          let hasMulti = _.find(subs, s => {
            let st = _.get(s, "def._node");
            return st === 'grid' || st === 'slider';
          });

          if(hasMulti) return false;
        }

      } else if(type === "prev" || type === 'next') {
        if(dragIsRoot && !dropNodeIsRoot) return false;
        // item 只能在根下或者根同级。
        if(!dragIsRoot && dropNodeIsRoot) return false;

        // let parentIsRoot = _.get(dropNode, "parent.data.def._node");
        let parentName = _.get(dropNode, "parent.data.name");
        let nodeType = _.get(dropDataDef, "_node");

        // layout 下只能是组件
        if((parentName === 'jzlLayout' || !parentName) && !dropNodeIsRoot) return false;
        if(nodeType === 'grid' || nodeType === 'slider') return false;
      }

      if(!dragIsRoot) {
        // 普通元素只能同组件下移动
        let dragRootCode = this.getNodeRootCode(draggingNode);
        let dropRootCode = this.getNodeRootCode(dropNode);

        if(!dragRootCode || dragRootCode !== dropRootCode) return false;
      }

      return true;
    },
    allowDrag(draggingNode) {
      // console.log(draggingNode)
      let nodeData = _.get(draggingNode, "data");
      let nodeDef = _.get(nodeData, "def");
      let isRoot = _.get(nodeData, "isRoot");
      let nodePropName = _.get(nodeData, "propName");
      // let nodePropPath = _.get(nodeData, "propPath");
      let nodeType = _.get(nodeDef, "_node");

      return isRoot || (nodeType !== 'grid' && nodeType !== 'slider' && nodePropName !== 'box_style' && nodePropName !== 'box_style'/* && nodePropPath !=='box_style.header'*/);
    },
    handleDropDone(draggingNode, dropNode, type, event) {
      // console.log(draggingNode, dropNode, type);
      this.$emit("node-drop-done", { draggingNode, dropNode, type, event});
    },

    getPageTitle(page, dftTitle) {
      return _.get(page, "page_name") || dftTitle
    },
    isEmptyPage(info) {
      return !info || !info.page_id;
    },
    closeOver() {
      // this.nodesPropShow = false;
      this.compAddPanelShow = false;
    },
    hideNodeProp() {
      this.nodesPropShow = false;
    },
    showNodeProp(propTab = 'style', isHover = false) {
      this.nodesPropShow = true;
      this.collapse = false;

      if(!isHover || propTab !== 'style' || this.propTab !== 'hover') {
        this.propTab = propTab;
      }
    },
    toggleNodeProp() {
      this.nodesPropShow = !this.nodesPropShow;

      if(this.nodesPropShow) {
        // this.propTab = 'style';
      }
      this.$emit('pinPropChange', this.nodesPropShow);
    },
    handleCollapseSwitch() {
      this.collapse = !this.collapse;
    },
    handleTempExpand() {
      this.tempExpand = true;

      if(this.tempExpandTimer) clearTimeout(this.tempExpandTimer);
      this.tempExpandTimer = setTimeout(() => { this.tempExpand = false }, 1200);
    },
    handleMouseEnter() {
      this.hoverExpand = true;
    },
    handleMouseLeave() {
      if(this.hoverExpandTimer) clearTimeout(this.hoverExpandTimer);
      this.hoverExpandTimer = setTimeout(() => { this.hoverExpand = false }, 1000);

      this.$emit('hoverElenode', null);
    },
    handlePropTabChange(tab) {
      this.propTab = tab;
    },
    copyNode(data) {
      let prop = _.get(data, "propName");
      let def = _.cloneDeep(_.get(data, "def"));

      if(!prop || !def) return;

      this.resetCode(def);

      let str = JSON.stringify({ prop, def });
      this.$utils.copyText(str);
    },
    async pasteNode(data) {
      let copiedText = await navigator.clipboard.readText();

      try {
        let json = JSON.parse(copiedText);
        let prop = _.get(json, "prop");
        let def = _.get(json, "def");

        if(!prop || !def) return;

        let xDef = _.get(data, "def");

        if(xDef[ prop ]) {
          prop = this.$utils.getNanoid(8);
        }

        xDef[ prop ] = def;

        this.$emit("eleNodeTreeChange")
      } catch (e) {}

    },
    pasteNodeReplace(data) {

    },
    copyItem() {
      let idx = this.getCurrentItemIndex();

      if(idx < 0) return;

      let orig = _.cloneDeep(this.currentItems[ idx ]);
      let code = this.$utils.getNanoid(8);
      let citem = _.defaultsDeep({
        page_item_code: code,
        alias: this._getAlias(code, this.items),
        project_id: this.projectId,
        module_name: code,
        i: code
      }, orig);   // _.merge({}, this.items[index]);

      delete citem.page_item_id;

      // let box_style = _.get(citem, "box_style");
      let ele_style = _.get(citem, "ele_style");

      // this.resetCode(box_style);
      this.resetCode(ele_style);

      this.currentItems.splice(idx + 1, 0, citem);
      this.$emit("eleNodeTreeChange")
    },
    handleCtrlC(data) {
      if(!data) return;
      if(data.isRoot) {
        this.copyItem(data);
      } else {
        this.copyNode(data);
      }
    },
    handleAddItem(menu, type) {

      let def = _.get(menu, "def");
      let vars = _.get(menu, "vars");
      let component = _.get(menu, 'component');

      if(!def) return;

      let eleDef = _.cloneDeep(def);
      let wrapDef = eleDef;
      let varsDef = _.cloneDeep(vars);

      if(component !== 'div' && component !== 'box') {
        if(type === 'box') {
          wrapDef = this.getNodeCompTpl('box');

          wrapDef.body[ component ] = eleDef;
        } else if(type === 'div') {
          wrapDef = this.getNodeCompTpl('div');
          wrapDef[ component ] = eleDef;
        }
      }

      //
      if(this.pageType == 1) {
        let width = _.get(wrapDef._ss, 'width') || 300;
        let height = _.get(wrapDef._ss, 'height') || 300;

        if(component === 'button') {
          width = 200;
          height = 50;
        } else if(component === 'icon') {
          width = 50;
          height = 50;
        } else if(component === 'text') {
          width = 300;
          height = 50;
        } else if(component === 'img') {
          width = 300;
          height = 300;
        } else if(component === 'c$navComp') {
          width = 500;
          height = 100;
        }

        if(!wrapDef._ss) wrapDef._ss = {};
        wrapDef._ss.position = "absolute";
        wrapDef._ss.width = width;
        wrapDef._ss.height = height;

        let pageWidth = this.pageWidth || 1920;
        let pageHeight = this.pageHeight || 1080;
        if(!_.hasIn(wrapDef._ss, 'left')) wrapDef._ss.left = (pageWidth - width) / 2;
        if(!_.hasIn(wrapDef._ss, 'top')) wrapDef._ss.top = (pageHeight - height) / 2;

        // wrapDef._ss.left = (1920 - width) / 2;
        // wrapDef._ss.top = (1080 - height) / 2;
      }

      this.$emit("create-page-item", {
        component: 'JzlItemComp',
        micro: true,
        // icon: 'fa fa-font',
        name: '模块',

        ele_style: wrapDef,    // this.getNodeCompTpl('div'),
        vars: varsDef
      });

      this.compAddPanelShow = false;
    },
    handleAddChildNodeCloud(compInfo) { // 云端组件作为 micro comp
      let comp_lib = _.get(compInfo, "comp_lib");
      let comp_name = _.get(compInfo, "comp_name");
      let comp_def = _.get(compInfo, "comp_def");

      if(!this.popData) return;

      let def = _.get(this.popData, "def");
      let name = this.getUniqNewPropName(def);

      if(!def) return;

      let newInfo = this.getNodeCompDefInfo(comp_def, this.currentItem);
      let info = _.get(newInfo, 'ele_style');
      let vars = _.get(newInfo, 'vars');
      let _code = this.$utils.getNanoid(10);

      this.currentItem.vars = (this.currentItem.vars || []).concat(vars);

      info._code = _code;
      info._lib = comp_lib;
      info._node = comp_name;

      if(!def._sort) {
        this.$set(def, '_sort', []);
        def._sort = [];
      }
      def._sort.push(name);
      this.$set(def, name, info);
      def[ name ] = info;

      // this.hideNodeMorePopover();
      this.$emit("changeElemNodes");

      this.$nextTick(() => {
        setTimeout(() => {
          this.$emit("selectItem", {
            targetEleName: _code,
            item: this.currentItem,
            items: this.currentItems
          });
        }, 100)
      });
    },
    handleShowMicroComps() {
      this.collapse = false;
      this.compAddPanelShow = true;
    },
    handleShowCloudComps(isCreateMicroComp = false) {
      this.collapse = false;
      this.compPanelShow = true;
      this.isCreateMicroComp = isCreateMicroComp === true;
      // this.$emit('show-cloud-comps')
    },
    handleCreateCloudComp(compInfo) {
      if(this.isCreateMicroComp) {
        this.handleAddChildNodeCloud(compInfo);
      } else {
        // this.$emit("create-page-item", comp);
        let comp_lib = _.get(compInfo, "comp_lib");
        let comp_name = _.get(compInfo, "comp_name");
        let comp_def = _.get(compInfo, "comp_def");

        let info = _.get(comp_def, 'ele_style');
        let vars = _.get(comp_def, 'vars');
        let _code = this.$utils.getNanoid(10);
        let component = _.get(comp_def, "component") || comp_name;

        info._code = _code;
        info._lib = comp_lib;
        info._node = comp_name;
        info._name = `Comp-${ comp_name }`;

        let eleDef = _.cloneDeep(info);
        let varsDef = _.cloneDeep(vars);
        let wrapDef = this.getNodeCompTpl('div');
        wrapDef[ component ] = eleDef;

        this.$emit("create-page-item", {
          component: 'JzlItemComp',
          micro: true,
          // icon: 'fa fa-font',
          name: '模块',

          ele_style: wrapDef,    // this.getNodeCompTpl('div'),
          vars: varsDef
        });
      }

      this.$jui.toast('添加成功！');
    },
    handleCloseCompPanel() {
      this.compAddPanelShow = false;
    },
    handleClearTagValue(nodeData) {
      if(nodeData && nodeData._value) {
        nodeData._value = "";
      }
    },
    handlePageItemSelectShow() {
      this.pageItemSelectWinShow = true;
    },
    handleCopyItem(item) {
      let code = this.$utils.getNanoid(10);
      let copyItem = _.defaultsDeep({
        page_item_code: code,
        alias: this._getAlias(code),
        project_id: this.projectId,
        module_name: code,
        i: code
      }, item);   // _.merge({}, this.items[index]);

      delete copyItem.page_item_id;

      let boxStyle = _.get(copyItem, "box_style");
      let eleStyle = _.get(copyItem, "ele_style");
      this.resetCode(boxStyle);
      this.resetCode(eleStyle);

      this.handleMenuClick(copyItem);
      this.pageItemSelectWinShow = false;
    },
    handleReferItem(item) {
      let code = this.$utils.getNanoid(10);
      let referItem = _.defaultsDeep({
        page_item_code: code,
        alias: this._getAlias(code),
        module_name: code,
        i: code,
        project_id: this.projectId,
        refer: item,
        refer_item_id: _.get(item, 'page_item_id')
      }, _.cloneDeep(referDef));

      this.handleMenuClick(referItem);
      this.pageItemSelectWinShow = false;
    },
    isCurrentSelected(data) {
      let isRoot = _.get(data, "isRoot");
      let pic = _.get(data, "item.page_item_code");
      let pic2 = _.get(this.currentItem, "page_item_code");

      return isRoot && pic && pic === pic2;
    }
  }
}
</script>

<template>
    <div class="ele-design-nodes" :class="{ 'fixed': panelFixed, 'collapse': collapse, 'expand': !collapse, 'moving': moving,'temp-expand': tempExpand,'hover-expand': hoverExpand }"
         v-draggable="nodeTreeDragProp" v-click-outside="closeOver" @mouseenter.stop="handleMouseEnter" @mouseleave.stop="handleMouseLeave">
        <div class="elem-node-tree" ref="nodesTreeContainer">

            <div class="elem-node-header elem-node-header-move" ref="nodeTreeDragHandler" @dblclick="handleCollapseSwitch">
                <div class="elem-node-tab">
                    <!--<i class="fa fa-grip-vertical elem-node-move"></i>-->
                    <el-popover v-model="compAddPanelShow" placement="bottom-start" width="300" trigger="manual">
                        <div slot="reference" class="elem-node-mulicon elem-node-move" @mousedown.stop
                             @click.stop="handleShowMicroComps" v-click-outside="handleCloseCompPanel"
                             v-tippy="{ arrow: true, placement: 'top' }" content="添加新模块"><i class="fa fa-plus-square1"></i>模块
                        </div>
                        <perfect-scrollbar class="ele-design-prop-eles ele-design-eles-pop">
                            <h5>添加新模块</h5>
                            <template v-for="(eles, prop) in tplCate">
                                <template v-if="prop !== 'formElems'">
                                    <ul>
                                        <el-row :gutter="5" style="width:100%">
                                            <el-col gutter="10" span="12" v-for="ele in eles">
                                                <li :key="ele.component"
                                                    @click="handleAddItem(ele)">
                                                    <i :class="ele.icon"></i>
                                                    <p v-text="ele.name"></p>
                                                    <template v-if="pageType != 1">
                                                        <i class="action-box fa fa-square1" v-if="ele.component !== 'div' && ele.component !== 'c$boxComp'"
                                                           @click.stop="handleAddItem(ele, 'div')"
                                                           v-tippy="{ arrow: true, placement: 'top' }" content="DIV容器中"></i>
                                                        <i class="action-box fa fa-window-maximize1" v-if="ele.component !== 'div' && ele.component !== 'c$boxComp'"
                                                           @click.stop="handleAddItem(ele, 'box')"
                                                           v-tippy="{ arrow: true, placement: 'top' }" content="Box容器中"></i>
                                                    </template>
                                                </li>
                                            </el-col>
                                        </el-row>
                                    </ul>
                                    <hr style="margin: 10px 0px 5px 0px;" />
                                </template>
                            </template>
                        </perfect-scrollbar>
                    </el-popover>
                    <div class="elem-node-mulicon elem-node-pluscloud" @mousedown.stop @click.stop="handleShowCloudComps(false)"
                         v-tippy="{ arrow: true, placement: 'top' }" content="添加云模块"><i class="jwdicon jwdicon-cloud-plus"></i>云模块</div>
                    <div class="elem-node-mulicon elem-node-pluscloud" @mousedown.stop @click.stop="handlePageItemSelectShow(false)"
                         v-tippy="{ arrow: true, placement: 'top' }" content="添加已有页面中模块"><i class="fa fa-google-plus-g"></i>页模块</div>
                </div>
            </div>
            <perfect-scrollbar class="ele-design-body-items xthin-scrollbar" @mouseleave="clearSelectEleNodeHoverTimeout" style="height: 100%">
                <el-tree ref="nodesTree"
                         class="menu-custom-tree builder-nodes-tree"
                         :data="elemNodes"
                         node-key="code"
                         indent="10"
                         :highlight-current="true"
                         :props="nodeTreeSetting"
                         :expand-on-click-node="false"
                         :auto-expand-parent="true"
                         :default-expanded-keys="expandKeys"
                         @click.native.stop="empty"
                         @node-click="handleSelectEleNodeClick"
                         @node-drop="handleDropDone"
                         draggable
                         empty-text="点击左上方按钮，添加新的模块"
                         :allow-drop="allowDrop"
                         :allow-drag="allowDrag">
                    <span slot-scope="{ node, data }" class="menu-custom-tree-node" tabindex="0"
                          @mouseover="handleSelectEleNodeHover(data, node, true)" @mouseleave="isNodeHover = false"
                          @click="handleSelectEleNodeClick(data, node)" @keydown.ctrl.67="handleCtrlC(data)" @keydown.ctrl.86="pasteNode(data)"
                          :class="{ 'builder-node-root': data.isRoot,
                                    'builder-node-selected': isCurrentSelected(data),
                                    'builder-node-allow-drag': allowDrag(node) }">
                        <i class="builder-node-type" :class="getNodeTypeIcon(data.def, data.isRoot)"
                           v-tippy="{ arrow: true, placement: 'left' }" :content="getNodeTypeLabel(data.def, data.isRoot)"></i>
                        <input v-if="data.nameEditing" v-model="data.name" type="text" v-focus
                               @blur="handleNameChg(data)" class="menu-tree-node-input" />
                        <span v-else v-text="data.name" class="menu-tree-node-title" @dblclick="data.nameEditing = true"></span>
                        <em v-if="data.isRoot" v-copy="data.alias"
                            v-tippy="{ arrow: true }" content="页面组件名，点击复制">-{{data.alias}}</em>
                        <i class="fa fa-circle-notch builder-node-btn-tip btn-first-tip" v-if="!data.isRoot && isMultipleNode(data.def)"
                           v-tippy="{ arrow: true }" content="循环节点"></i>
                        <!--<i class="fa fa-erlang builder-node-btn-tip" v-if="!data.isRoot && data.def && data.def._evts && data.def._evts.length"
                           v-tippy="{ arrow: true }" content="节点有事件"></i>-->
                        <i class="fa fa-monero builder-node-btn-tip" v-if="isModelNode(data.def)"
                           v-tippy="{ arrow: true }" content="数据绑定（双向）"></i>
                        <i class="fa fa-mix builder-node-btn-tip" v-else-if="isDataNode(data.def)"
                           v-tippy="{ arrow: true }" content="数据展示（显示）"></i><!-- @click="showNodeProp('data', data)" -->
                        <i class="fa fa-etsy builder-node-btn-tip" v-if="data.def && data.def._evts && data.def._evts.length"
                           v-tippy="{ arrow: true }" content="已绑事件"></i>
                        <el-popconfirm title="确定删除当前节点?" @confirm="handleRemove(data)">
                            <i slot="reference" class="btn-more el-icon-delete builder-node-btn-style"></i>
                        </el-popconfirm>

                        <i class="el-icon-plus btn-more builder-node-btn-event" v-if="!isFixNode(data) && !isLeafNode(data.def)"
                           v-tippy="{ arrow: true }" content="添加节点" @click="showNodeMorePopover($event, data)"></i>
                    </span>
                </el-tree><!-- :default-expand-all="true" -->
            </perfect-scrollbar>
        </div>
        <div style="display: flex;position:fixed; right:0px;top: 41px;bottom: 0px;">
            <div class="ele-design-node-tools page-builder-item-tools"><!-- v-if="popData && currentItem && currentItem.page_item_code" -->
                <div style="width: 100%;">

                    <div class="page-builder-item-tab" :class="{ 'active': propTab === 'item' }"
                         @click="showNodeProp('item')" v-tippy="{ arrow: true, placement: 'right' }" content="模块 创建/变量">
                        <i class="jwdicon jwdicon-Variable div"></i>模块变量</div>
                    <div class="page-builder-item-tab" :class="{ 'active': propTab === 'data' }"
                         @click="showNodeProp('data')" v-tippy="{ arrow: true, placement: 'right' }" content="节点显示数据">
                        <i class="el-icon-setting div"></i> 节点设置
                    </div>
                    <div class="page-builder-item-tab" :class="{ 'active': propTab === 'style' || propTab === 'hover' }"
                         @click="showNodeProp('style')" v-tippy="{ arrow: true, placement: 'right' }" content="节点样式">
                        <i class="jwdicon jwdicon-css div"></i>节点样式
                    </div><!--  @mouseenter="showNodeProp('style', true)"-->
                    <div style="display: flex;justify-content: center;align-items: center;height: 40px;">

                    </div>
                </div>

                <div style="padding-bottom: 8px;">
                    <div class="page-builder-panel-collapse fa fa-chevron-left" :class="{ 'rotate': nodesPropShow }"
                         @click="toggleNodeProp"></div>
                    <!-- :class="{ 'fa-chevron-left': nodesPropShow, 'fa-chevron-right': !nodesPropShow }" -->
                </div>

            </div>
            <builder-nodes-prop :class="{ 'expand': nodesPropShow }" v-bind="$attrs" v-on="$listeners"
                                :current-item="currentItem" :current-items="currentItems" :current-page="currentPage"
                                :current-item-el-code="currentItemElCode" :elem-nodes="elemNodes" :prop-tab="propTab" :pop-data="popData"
                                @tabChange="handlePropTabChange"></builder-nodes-prop>
        </div>

        <el-popover ref="nodeMorePopover" popper-class="popover-dropdown-menu el-dropdown-menu--small"
                    placement="right-start" trigger="hover">
            <div style="height: 600px;width: 303px;">
                <builder-nodes-add :current-item="currentItem" :current-items="currentItems" :pop-data="popData" :current-node="currentNode"
                                   theme="mini" @close="hideNodeMorePopover" v-bind="$attrs" v-on="$listeners"></builder-nodes-add>
            </div>
        </el-popover>

        <el-popover ref="nodeActionPopover" popper-class="popover-tooltip"
                    v-model="nodeActionPopVisible" placement="bottom-start" :visible-arrow="false" :offset="0" trigger="click">
            <div class="design-popover-icons">
                <el-popover popper-class="popover-dropdown-menu el-dropdown-menu--small"
                            v-model="nodeValuePopVisible" placement="bottom-start" trigger="hover">
                    <node-data-value v-if="nodeValuePopVisible && popData && popData.def" style="min-width:320px;"
                                     v-model="popData.def._value" :item="currentItem" :page="currentPage"
                                     :current-ele-data="currentEleData" :current-node="currentNode" :elem-nodes="elemNodes"
                                     v-bind="$attrs" :disabled="!isDataEnable"></node-data-value>
                    <i slot="reference" class="design-popover-icon jwdicon jwdicon-Variable"></i>
                </el-popover>

                <el-popover v-if="currentEleData && currentEleData._node === 'text'"
                            popper-class="popover-dropdown-menu el-dropdown-menu--small" placement="bottom-start" trigger="hover">
                    <div style="padding: 0px 5px">
                        <div v-if="currentEleData._value" style="font-size: 12px;margin-bottom:5px;font-weight: bold">注：已设置变量，生效静态内容需
                            <a href="javascript:;" @click="handleClearTagValue(currentEleData)">清除变量</a>
                        </div>
                        <el-input v-if="currentEleData && currentEleData._ss" placeholder="请输入内容" style="width: 260px"
                                  v-model="currentEleData._ss.text" type="textarea" :rows="3"></el-input>
                    </div>
                    <i slot="reference" class="design-popover-icon jwdicon jwdicon-text1"></i>
                </el-popover>

                <el-popover v-if="currentEleData && currentEleData._node === 'icon'"
                            popper-class="popover-dropdown-menu el-dropdown-menu--small" placement="bottom-start" trigger="hover">
                    <div style="padding: 0px 5px">
                        <el-button type="primary" plain size="mini" @click="handleShowNodeIconWin">重选</el-button>
                        <el-button size="mini" @click="handleClearNodeProp('icon')">清除</el-button>
                    </div>
                    <i slot="reference" class="design-popover-icon jwdicon jwdicon-i" @click="handleShowNodeIconWin"></i>
                </el-popover>
                <el-popover v-if="currentEleData && currentEleData._node === 'img'"
                            popper-class="popover-dropdown-menu el-dropdown-menu--small" placement="bottom-start" trigger="hover">
                    <div style="padding: 0px 5px">
                        <el-button type="primary" plain size="mini" @click="handleShowNodeImgWin">重选</el-button>
                        <el-button size="mini" @click="handleClearNodeProp('img')">清除</el-button>
                    </div>
                    <i slot="reference" class="design-popover-icon jwdicon jwdicon-image" @click="handleShowNodeImgWin"></i>
                </el-popover>

                <el-popover ref="nodeFormulaPopover" popper-class="popover-dropdown-menu el-dropdown-menu--small"
                            v-model="nodeFormulaPopVisible" placement="bottom-start" trigger="hover">
                    <node-formula-render v-if="currentEleData" ref="nodeFormulaInput" style="padding: 5px 10px;"
                                         v-model="currentEleData._formula" v-bind="$attrs" :item="currentItem" :page="currentPage"
                                         :current-ele-data="currentEleData" :current-node="currentNode" :elem-nodes="elemNodes"
                                         :disabled="!isDataEnable"></node-formula-render>
                    <i slot="reference" class="design-popover-icon jwdicon jwdicon-biaoge-hanshu"
                       v-tippy :content="`渲染公式: ${ (currentEleData && currentEleData._formula) || '无' }`"></i>
                </el-popover>
                <el-popover ref="nodeLowcodePopover" popper-class="popover-dropdown-menu el-dropdown-menu--small"
                            v-model="nodeLowcodePopVisible" placement="bottom-start" trigger="hover">
                    <builder-nodes-lowcode :current-ele-data="currentEleData" :page="currentPage" v-bind="$attrs"></builder-nodes-lowcode>
                    <i slot="reference" class="design-popover-icon jwdicon jwdicon-Code" v-tippy content="低码"></i>
                </el-popover>

                <el-popover ref="nodeEventPopover" popper-class="popover-dropdown-menu el-dropdown-menu--small"
                            v-model="nodeEventPopVisible" placement="bottom-start" trigger="hover">
                    <div class="elem-design-prop-logic" style="width: 280px;">
                        <h5><span>事件</span></h5>
                        <event-tags v-model="currentEleData._evts" :page="currentPage" :page-item-code="currentItem && currentItem.page_item_code"
                                    :support="currentEleData._se" :lowcode="lowcode"></event-tags>
                    </div>
                    <i slot="reference" class="design-popover-icon jwdicon jwdicon-click" v-tippy content="事件"></i>
                </el-popover>

                <el-popover v-if="isMicroComp(currentEleData)"
                            popper-class="popover-dropdown-menu el-dropdown-menu--small"
                            placement="bottom-start" trigger="hover">
                    <div class="elem-design-prop-logic" style="width: 280px;">
                        <h5>扩展属性</h5>
                        <builder-node-propext :ele-def="currentEleData" v-bind="$attrs" :item="currentItem" :page="currentPage"
                                              :current-ele-data="currentEleData" :current-node="currentNode" :elem-nodes="elemNodes"></builder-node-propext>
                    </div>
                    <i slot="reference" class="design-popover-icon el-icon-setting" v-tippy content="设置"></i>
                </el-popover>

                <el-popover popper-class="popover-dropdown-menu el-dropdown-menu--small"
                            placement="bottom" trigger="hover"
                            v-if="!isFixNode(popData) && !isLeafNode(popData && popData.def)">
                    <div style="height: 300px;width: 690px;">
                        <builder-nodes-add :current-item="currentItem" :current-items="currentItems" :pop-data="popData" :current-node="currentNode"
                                           theme="mini" v-bind="$attrs" v-on="$listeners"></builder-nodes-add>
                    </div>
                    <i slot="reference" class="design-popover-icon el-icon-plus" v-tippy content="添加子节点"></i>
                </el-popover>

                <i class="design-popover-icon jwdicon jwdicon-cloud-plus" v-tippy content="添加云组件"
                   @click="handleShowCloudComps(true)"></i>

                <i class="design-popover-icon el-icon-delete" v-tippy content="删除" @click="handleRemove(popData)"></i>
            </div>
        </el-popover>

        <el-drawer :title="compPanelName" :visible.sync="compPanelShow" :append-to-body="true"
                   :with-header="false" size="450px"
                   direction="btt" class="page-builder-container" style="background: none;top: 0px;">
            <builder-comps-cloud v-if="compPanelShow" @create-page-comp="handleCreateCloudComp"></builder-comps-cloud>
        </el-drawer>

        <el-drawer title="选择已有页面组件" :visible.sync="pageItemSelectWinShow" :append-to-body="true"
                   :with-header="false" size="450px"
                   direction="btt" class="page-builder-container" style="background: none;top: 0px;">
            <page-item-picker :query-page-type="pageType" @copyItem="handleCopyItem" @referItem="handleReferItem"
                              @close="pageItemSelectWinShow = false"></page-item-picker>
        </el-drawer>
    </div>
</template>

<style lang="scss" scoped>
.ele-design-eles-pop {
    border: none;
    background: none;
    margin: -5px -10px 0px -5px;

    .page-builder-menu-group {
        padding: 0px;
    }

    ul {
        font-size: 12px;

        li {
            margin: 5px 0px 0px 0px;
            width: 100%;
            border-radius: 2px;
            padding: 0px 0px 0px 8px;
            height: 32px;
            background: #F5F9FF;
            font-size: 12px;

            &:hover {
                color: #105EBF;
            }

            i {
                font-size: 14px;
            }
            p {
                flex: 1;
                font-weight: bold;
            }

            .action-box {
                width: 28px;
                height: 28px;
                background: #F5F9FA;
                color: #105EBF;
                margin: 1px;
                display: flex;
                align-items: center;
                justify-content: center;
                border-left: 1px solid #EEE;
                opacity: .2;

                &:hover {
                    background: #105EBF;
                    color: #FFF;
                }
            }

            &:hover {
                .action-box {
                    opacity: 1;
                }
            }
        }
    }
}
</style>
